package com.jxpanda.infrastructure.core.tollkit.json;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonStreamContext;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.PackageVersion;
import com.jxpanda.infrastructure.core.constant.StringConstant;
import com.jxpanda.infrastructure.core.constant.UriSchemeConstant;
import com.jxpanda.infrastructure.core.tollkit.StringKit;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Panda
 */
public class ImageModule extends SimpleModule {

    private static final String SEPARATOR = StringConstant.SLASH;

    /**
     * 图片域名
     */
    private final String domain;

    /**
     * 代理的字段，这些字段命名的属性会被代理
     * 然后把图片地址前缀替换掉
     */
    private final Set<String> fieldSet;

    public ImageModule() {
        this(StringConstant.BLANK, defaultFieldSet());
    }

    public ImageModule(String domain) {
        this(domain, defaultFieldSet());
    }

    public ImageModule(String domain, Set<String> fieldSet) {
        super(PackageVersion.VERSION);
        this.domain = stickDomain(domain);
        this.fieldSet = fieldSet;
        addSerializer(String.class, new JsonSerializer<>() {
            @Override
            public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                if (isImageField(gen.getOutputContext())) {
                    gen.writeString(handled(value));
                } else {
                    gen.writeString(value == null ? "" : value);
                }
            }
        });
    }

    public String handled(String image) {
        if (StringKit.isBlank(image)) {
            return StringConstant.BLANK;
        }
        return (image.startsWith(UriSchemeConstant.HTTP) || image.startsWith(UriSchemeConstant.HTTPS)) ? image : stickImage(image);
    }

    private static String stickDomain(String domain) {
        if (!domain.startsWith(UriSchemeConstant.HTTP) && !domain.startsWith(UriSchemeConstant.HTTPS)) {
            domain = UriSchemeConstant.HTTPS + domain;
        }
        return domain.endsWith(SEPARATOR) ? domain : (domain + SEPARATOR);
    }

    private String stickImage(String image) {
        String imageWithNoDomain = image.startsWith(SEPARATOR) ? image.substring(1) : image;
        if (!imageWithNoDomain.contains(StringConstant.PERCENT_SIGN)) {
            imageWithNoDomain = URLEncoder.encode(imageWithNoDomain, StandardCharsets.UTF_8);
        }
        return this.domain + imageWithNoDomain;
    }

    private boolean isImageField(JsonStreamContext context) {
        String currentName = context.getCurrentName();
        if (currentName == null && context.getParent() != null) {
            currentName = context.getParent().getCurrentName();
        }
        String field = currentName;
        return fieldSet.stream().anyMatch(it -> field != null && field.equals(it));
    }

    public static Set<String> defaultFieldSet() {
        return Stream.of("image", "images", "imageList",
                        "img", "imgList",
                        "picture", "pictures", "pictureList",
                        "icon", "icons", "iconList",
                        "pic", "pics", "picList")
                .collect(Collectors.toSet());
    }

    public void addField(String fieldName) {
        this.fieldSet.add(fieldName);
    }

    public void removeField(String fieldName) {
        this.fieldSet.remove(fieldName);
    }

}
